/*
 * Copyright (C) <2009>
 * <Rishi B Agrawal> <Sneha Hendre>
 * <rishi.b.agrawal@gmail.com> <sneha.hendre@gmail.com>
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include "../include/ohsm.h"
#include "ohsm_u.h"

int
get_relops(char *temp_relop) {
	if (!strcmp (temp_relop, "LT"))
		return LT;
	else if (!strcmp (temp_relop, "GT"))
		return GT;
	else if (!strcmp (temp_relop, "EQ"))
		return EQ;
	else if (!strcmp (temp_relop, "NEQ"))
		return NEQ;
	else if (!strcmp (temp_relop, "LE"))
		return LE;
	else if (!strcmp (temp_relop, "GE"))
		return GE;
	else
		return -1;
}

int
parse_when(xmlDocPtr doc, xmlNodePtr cur) {
	int retval, no;
	long long temp;
	xmlChar *key;
	retval = no = 0;
	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL) {
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FSIZE"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			relocpol->policy[relocpol->pidx].reloc_criteria_bitmap |= FSIZE;
			temp = validate_id_long(key);
			if (temp == -1) {
				no =  (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : wrong value in <FSIZE> tag ", no);
				return -1;
			}
			relocpol->policy[relocpol->pidx].values[0] = temp;
			xmlFree(key);
			cur = cur->next;
			if ((!xmlStrcmp(cur->name, (const xmlChar *) "REL"))) {
				key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
				retval = (int) get_relops((char *) key);
				if (retval == -1) {
					no = (int) xmlGetLineNo(cur);
					printf("\nOHSM: [%d] : wrong value in <REL> tag", no);
					return retval;
				}
				relocpol->policy[relocpol->pidx].rel_ops[0] = retval;
				xmlFree(key);
			}
			if (cur->next->next)
				cur = cur->next->next;
			else
				return 0;
		}
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FMA"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			relocpol->policy[relocpol->pidx].reloc_criteria_bitmap |= FMA;
			temp = validate_id_long(key);
			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : wrong value in <FMA> tag ", no);
				return temp;
			}
			relocpol->policy[relocpol->pidx].values[1] = temp;
			xmlFree(key);
			cur = cur->next;
			if ((!xmlStrcmp(cur->name, (const xmlChar *) "REL"))) {
				key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
				retval = (int) get_relops((char *) key);
				if (retval == -1) {
					no = (int) xmlGetLineNo(cur);
					printf("\nOHSM: [%d] : wrong value in <REL> tag", no);
					return retval;
				}
				relocpol->policy[relocpol->pidx].rel_ops[1] = retval;
				xmlFree(key);
			}
			if (cur->next->next)
				cur = cur->next->next;
			else
				return 0;
		}
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FAA"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			relocpol->policy[relocpol->pidx].reloc_criteria_bitmap |= FAA;
			temp = validate_id_long(key);
			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : wrong value in <FAA> tag ", no);
				return temp;
			}
			relocpol->policy[relocpol->pidx].values[2] = temp;
			xmlFree(key);
			cur = cur->next;
			if ((!xmlStrcmp(cur->name, (const xmlChar *) "REL"))) {
				key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
				retval = (int) get_relops((char *) key);
				if (retval == -1) {
					no = (int) xmlGetLineNo(cur);
					printf("\nOHSM: [%d] : wrong value in <REL> tag", no);
					return retval;
				}
				relocpol->policy[relocpol->pidx].rel_ops[2] = retval;
				xmlFree(key);
			}
			if (cur->next->next)
				cur = cur->next->next;
			else
				return 0;
		}
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FIOT"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			relocpol->policy[relocpol->pidx].reloc_criteria_bitmap |= FIOT;
			temp = validate_id_long(key);
			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : wrong value in <FIOT> tag ", no);
				return temp;
			}
			relocpol->policy[relocpol->pidx].values[3] = temp;
			xmlFree(key);
			cur = cur->next;
			if ((!xmlStrcmp(cur->name, (const xmlChar *) "REL"))) {
				key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
				retval = (int) get_relops((char *) key);
				if (retval == -1) {
					no = (int) xmlGetLineNo(cur);
					printf("\nOHSM: [%d] : wrong value in <REL> tag", no);
					return retval;
				}
				relocpol->policy[relocpol->pidx].rel_ops[3] = retval;
				xmlFree(key);
			}
			if (cur->next->next)
				cur = cur->next->next;
			else
				return 0;
		}
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FAT"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			relocpol->policy[relocpol->pidx].reloc_criteria_bitmap |= FAT;
			temp = validate_id_long(key);
			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : wrong value in <FAT> tag ", no);
				return temp;
			}
			relocpol->policy[relocpol->pidx].values[4] = temp;
			xmlFree(key);
			cur = cur->next;
			if ((!xmlStrcmp(cur->name, (const xmlChar *) "REL"))) {
				key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
				retval = (int) get_relops((char *) key);
				if (retval == -1) {
					no = (int) xmlGetLineNo(cur);
					printf("\nOHSM: [%d] : wrong value in <REL> tag", no);
					return retval;
				}
				relocpol->policy[relocpol->pidx].rel_ops[4] = retval;
				xmlFree(key);
			}
			if (cur->next->next)
				cur = cur->next->next;
			 else
				return 0;
		}
	}
	return 0;
}

int
parse_single_rule(xmlDocPtr doc, xmlNodePtr cur) {
	int retval, temp, no, error;
	xmlChar *key;
	retval = temp = no = error = 0;
	cur = cur->xmlChildrenNode;
	cur = cur->next;
	relocpol->policy[relocpol->pidx].reloc_criteria_bitmap = 0;
	while (cur != NULL) {
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "FROM"))) {
			key = xmlNodeListGetString(doc,	cur->xmlChildrenNode, 1);
			temp = validate_key(key);
			if (temp == -1 || temp == 0) {
				printf("\nOHSM: invalid tier value in tier tag\n");
				return -1;
			}
			relocpol->policy[relocpol->pidx].src_tier = temp;
			xmlFree(key);
		}
		cur = cur->next->next;
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "TO"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			temp = validate_key(key);
			if (temp == -1 || temp == 0) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : invalid tier value in tier tag\n", no);
				return -1;
			}
			relocpol->policy[relocpol->pidx].dest_tier = temp;
			xmlFree(key);
		}
		cur = cur->next->next;
		if (!cur)
			return 0;
		if ((!xmlStrcmp(cur->name, (const xmlChar *) "WHEN"))) {
			relocpol->policy[relocpol->pidx].rel_ops[0] = 0;
			relocpol->policy[relocpol->pidx].rel_ops[1] = 0;
			relocpol->policy[relocpol->pidx].rel_ops[2] = 0;
			relocpol->policy[relocpol->pidx].rel_ops[3] = 0;
			relocpol->policy[relocpol->pidx].rel_ops[4] = 0;
			relocpol->policy[relocpol->pidx].values[0] = 0;
			relocpol->policy[relocpol->pidx].values[1] = 0;
			relocpol->policy[relocpol->pidx].values[2] = 0;
			relocpol->policy[relocpol->pidx].values[3] = 0;
			relocpol->policy[relocpol->pidx].values[4] = 0;
			retval = parse_when(doc, cur);
			if (retval == -1)
				error = SET;
		}
		cur = cur->next->next;
	}
	if (error)
		return -1;
	return 0;
}
int
parse_doc_rel(char *docname) {
	int temp, no, cnt_policies, retval, error;
	xmlDocPtr doc;
	xmlNodePtr cur;
	xmlChar *key = NULL;
	temp = no = cnt_policies = retval = error = 0;
	doc = xmlParseFile(docname);
	xmlLineNumbersDefault(1);
	if (!doc) {
		printf("\nOHSM: Error: Document not parsed successfully");
		xmlFreeDoc(doc);
		return -1;
	}
	cur = xmlDocGetRootElement(doc);
	if (!cur) {
		printf("\nOHSM: Error: Empty document %s", docname);
		xmlFreeDoc(doc);
		return -1;
	}
	if (xmlStrcmp(cur->name, (const xmlChar *) "RELOC_POLICY")) {
		printf("\nOHSM: Error: Invalid document Root element not equal to <RELOC_POLICY>...%s", docname);
		xmlFreeDoc(doc);
		return -1;
	}
	cur = cur->xmlChildrenNode;
	cur = cur->next;
		if ((!xmlStrcmp(cur->name, (xmlChar *) "NR_RULES"))) {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			temp = validate_key(key);
			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				printf("\nOHSM: Error: [%d] : wrong value in <NR_RULES> tag", no);
				printf("\nOHSM: Error: [%d] : fatal : cannot proceed further", no);
				return temp;
			}
			if (relocpol == NULL)
				printf("\n\nError in Relocation policy %s", docname);
			relocpol->cnt_policies = temp;
			cur = cur->next->next;
			while (cur != NULL) {
				if ((!xmlStrcmp(cur->name, (const xmlChar *) "RULE"))) {
					cnt_policies++;
					retval = parse_single_rule(doc, cur);
					if (retval == -1)
						error = SET;
					relocpol->pidx++;
				}
				cur = cur->next->next;
			}
		}
	if (cnt_policies != relocpol->cnt_policies) {
		no = (int) xmlGetLineNo(cur);
		printf("\nOHSM: [%d] : wrong value in <NR_RULE> number of rules different then entered RULES", no);
		return -1;
	}
	xmlFreeDoc(doc);
	if (error)
		return -1;
	return 0;
}

int
ohsm_get_relocation_policy(char *filename) {
	int retval = 0;
	char cmd[80] = "";
	sprintf(cmd, "xmllint --valid --noout %s", filename);
	retval = system(cmd);
	if (retval) {
		printf("\nOHSM: error in tags of %s \nrefer DTD file", filename);
		return -1;
	}
	retval = parse_doc_rel(filename);
	return retval;
}

